﻿using System;
using System.Reactive.Linq;
using System.Xml;

namespace Wulong.Phone.Dianping.Utils
{
    /// <summary>
    /// A series convienent extension helpers for <see cref="System.Xml.XmlReader"/>
    /// All credits go to Tim Greenfield http://programmerpayback.com
    /// </summary>
    public static class XmlReaderExtensions
    {
        /// <summary>
        /// Move the reader to the specified XML element
        /// see details at http://programmerpayback.com/2010/03/22/silverlight-rx-dataclient-within-mvvm/
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="elementName">The name of element</param>
        /// <returns>true if found or else false</returns>
        public static bool GoToElement(this XmlReader reader, string elementName)
        {
            do
                if (reader.NodeType == XmlNodeType.Element && reader.Name == elementName)
                    return true;
            while (reader.Read());
            return false;
        }

        /// <summary>
        /// Convert the XmlReader to an IObservable and thus provide you with the SAX-like XML parsing
        /// You can also benefit with usage of LINQ expressions to select on specific nodes in the Xml
        /// see details at http://programmerpayback.com/2010/03/22/reactive-xmlreader-for-sax-like-parsing/
        /// </summary>
        /// <example>
        /// <code>
        /// <![CDATA[
        /// XmlReader reader = XmlReader.Create(“TreeOfLife.xml”);
        /// IObservable<XmlReader> RxReader = reader.ToObservable();
        /// IObservable<string> NameFinder = from nodeReader in RxReader
        ///                                     where nodeReader.NodeType == XmlNodeType.Element && nodeReader.Name == “NAME”
        ///                                     select nodeReader.ReadElementContentAsString();
        /// NameFinder.Subscribe((item) => names.Add(item));
        /// ]]>
        /// </code>
        /// </example>
        /// <param name="reader">specifies XmlReader as the type that the method operates on</param>
        /// <returns></returns>
        public static IObservable<XmlReader> ToObservable(this XmlReader reader)
        {
            return Observable.Create<XmlReader>(observer =>
            {
                try
                {
                    while (reader.Read())
                        observer.OnNext(reader);
                    observer.OnCompleted();
                }
                catch (Exception e)
                {
                    observer.OnError(e);
                }
                return reader;
            });
        }
    }
}
